/*
 *  Copyright (c) 2011 Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *  Contributors:
 *      Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany - RMI Client, FileChooser and WebDAV
 */
package de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.metadata;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.log4j.Logger;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.DataFormat;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.DataSize;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.DataType;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.DirectoryMetaData;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.EnumDublinCoreElements;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaData;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaDataException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.UntypedData;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientDataManager;

@XmlRootElement
public class Property {
	private String title;
	private String description;
	private String subject;
	private PersonWrapper contributor;
	private String coverage;
	private PersonWrapper creator;	
	private EdalLanguageWrapper language;
	
	private String rights;
	private String source;

	private BasicDateWrapper date;
	private DateEventsWrapper events;
	private IdentifierWrapper identifier;
	private IdentifierRelationWrapper identifierRelation;
	@XmlAttribute
	private final long version;
	@XmlAttribute
	private final long size;
	@XmlAttribute
	private final String format;
	@XmlAttribute
	private final String type;
	@XmlAttribute
	private final boolean deleted;
	/**
	 * Standard constuctor. Has to exist in order to use this Class for
	 * unmarshalling Xml-Documents into Java-Objetcs.
	 * 
	 * @see javax.xml.bind.JAXBContext
	 */
	public Property() {
		this.version = 0L;
		this.size = 0L;
		this.format = "Unknown";
		this.type = "Unknown";
		this.deleted = false;
	};

	/**
	 * Provides an Object for Marshalling Xml-Documents in order to view and
	 * edit MetaData of PrimaryDataEntities.
	 * 
	 * @param metaData
	 *            MetaData to use
	 * @param revision
	 *            revision of the version linked to this MetaData
	 * @param deleted
	 *            true i the linked version is deleted
	 * @see de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaData
	 */
	public Property(final MetaData metaData, final long revision,
			boolean deleted) throws MetaDataException {
		// set document title
		this.title = metaData.getElementValue(EnumDublinCoreElements.TITLE)
				.getString();

		// set MetaData version
		this.version = revision;

		UntypedData data = metaData
				.getElementValue(EnumDublinCoreElements.SIZE);

		// set entity size
		this.size = ((DataSize) data).getFileSize().longValue();

		// set description
		this.description = metaData.getElementValue(
				EnumDublinCoreElements.DESCRIPTION).getString();

		// set data format
		data = metaData.getElementValue(EnumDublinCoreElements.FORMAT);
		if (data instanceof DataFormat) {
			this.format = ((DataFormat) data).getMimeType();
		} else {
			this.format = "Unknown";
		}
		
		// set subject
		this.subject = metaData.getElementValue(EnumDublinCoreElements.SUBJECT)
				.getString();

		// set DataType
		data = metaData.getElementValue(EnumDublinCoreElements.TYPE);
		if (data instanceof DataType) {
			this.type = ((DataType) data).getDataType().toString();
		} else if (DirectoryMetaData.class.isInstance(data)) {
			this.type = "Directory";
		} else {
			this.type = "Unknown";
		}

		// set contributor
		data = metaData.getElementValue(EnumDublinCoreElements.CONTRIBUTOR);
		if (data instanceof de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.NaturalPerson) {
			this.contributor = new NaturalPersonWrapper(
					(de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.NaturalPerson) data);
		} else if (data instanceof de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.LegalPerson) {
			this.contributor = new LegalPersonWrapper(
					(de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.LegalPerson) data);
		}

		// set coverage
		this.coverage = metaData.getElementValue(
				EnumDublinCoreElements.COVERAGE).getString();

		// set creator
		data = metaData.getElementValue(EnumDublinCoreElements.CREATOR);
		if (data instanceof de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.NaturalPerson) {
			this.creator = new NaturalPersonWrapper(
					(de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.NaturalPerson) data);
		} else if (data instanceof de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.LegalPerson) {
			this.creator = new LegalPersonWrapper(
					(de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.LegalPerson) data);
		}

		this.deleted = deleted;

		// set date information
		data = metaData.getElementValue(EnumDublinCoreElements.DATE);
		if (de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.DateEvents.class
				.isInstance(data)) {
			this.events = new DateEventsWrapper(
					(de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.DateEvents) data);
		}

		// set identifer
		data = metaData.getElementValue(EnumDublinCoreElements.IDENTIFIER);
		if (de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.Identifier.class
				.isInstance(data)) {
			this.identifier = new IdentifierWrapper(
					(de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.Identifier) data);
		}

		// set Language
		data = metaData.getElementValue(EnumDublinCoreElements.LANGUAGE);		
		this.language = new EdalLanguageWrapper(
				(de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.EdalLanguage) data);
		

		// set relation
		data = metaData.getElementValue(EnumDublinCoreElements.RELATION);
		if (de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.IdentifierRelation.class
				.isInstance(data)) {
			this.identifierRelation = new IdentifierRelationWrapper(
					(de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.IdentifierRelation) data);
		}

		// set rights
		this.rights = metaData.getElementValue(EnumDublinCoreElements.RIGHTS)
				.getString();

		// set rights
		this.source = metaData.getElementValue(EnumDublinCoreElements.SOURCE)
				.getString();
	}

	public void setEvents(DateEventsWrapper events) {
		this.events = events;
	}

	public void setIdentifier(IdentifierWrapper identifier) {
		this.identifier = identifier;
	}

	public void setIdentifierRelation(IdentifierRelationWrapper identifierRelation) {
		this.identifierRelation = identifierRelation;
	}

	public void setCreator(PersonWrapper creator) {
		this.creator = creator;
	}

	public void setDate(BasicDateWrapper date) {
		this.date = date;
	}

	public PersonWrapper getContributor() {
		return this.contributor;
	}

	public String getCoverage() {
		return this.coverage;
	}

	public PersonWrapper getCreator() {
		return this.creator;
	}

	public String getDescription() {
		return this.description;
	}

	public String getFormat() {
		return this.format;
	}

	public long getSize() {
		return this.size;
	}

	public String getSubject() {
		return this.subject;
	}

	// getters and setters
	public String getTitle() {
		return this.title;
	}

	public boolean getDeleted() {
		return this.deleted;
	}

	public String getType() {
		return this.type;
	}

	public long getVersion() {
		return this.version;
	}
	
	public EdalLanguageWrapper getLanguage() {
		return language;
	}
	
	public String getRights() {
		return rights;
	}

	public String getSource() {
		return source;
	}

	public BasicDateWrapper getDate() {
		return date;
	}

	public DateEventsWrapper getEvents() {
		return events;
	}

	public IdentifierWrapper getIdentifier() {
		return identifier;
	}

	public IdentifierRelationWrapper getIdentifierRelation() {
		return identifierRelation;
	}

	public static Logger getLog() {
		return ClientDataManager.logger;
	}

	public void setSource(String source) {
		this.source = source;
	}

	public void setRights(String rights) {
		this.rights = rights;
	}
	
	public void setLanguage(EdalLanguageWrapper language) {
		this.language = language;
	}
	
	public void setContributor(PersonWrapper contributor) {
		this.contributor = contributor;
	}

	public void setCoverage(final String coverage) {
		this.coverage = coverage;
	}


	public void setDescription(final String description) {
		this.description = description;
	}

	public void setSubject(final String subject) {
		this.subject = subject;
	}

	public void setTitle(final String title) {
		this.title = title;
	}

	/**
	 * Used to update a given instance of MetaData after unmarshalling a
	 * properties.xml to a Property Object.
	 * 
	 * @param m
	 *            the MetaData-Object to write to
	 */
	public void updateMetaData(final MetaData m) {
		try {
			// these are all readable and writable values
			m.setElementValue(EnumDublinCoreElements.TITLE, new UntypedData(
					this.title));
			m.setElementValue(EnumDublinCoreElements.DESCRIPTION,
					new UntypedData(this.description));
			m.setElementValue(EnumDublinCoreElements.SUBJECT, new UntypedData(
					this.subject));
			m.setElementValue(EnumDublinCoreElements.CONTRIBUTOR,
					this.contributor.getPerson());
			m.setElementValue(EnumDublinCoreElements.CREATOR,
					this.creator.getPerson());
			m.setElementValue(EnumDublinCoreElements.COVERAGE, new UntypedData(
					this.coverage));			
			m.setElementValue(EnumDublinCoreElements.LANGUAGE,
					this.language.getEdalLanguage());
			m.setElementValue(EnumDublinCoreElements.RIGHTS, new UntypedData(
					this.rights));
			m.setElementValue(EnumDublinCoreElements.SOURCE, new UntypedData(
					this.source));
		} catch (final MetaDataException e) {
			Property.getLog().error(
					"Failed to update meta data: " + e.toString());
		}
	}
}
